/*
 * @brief:
 *      选针器对象
 *
 * ChangeLog        Author          Notes
 * 2015.09.08       Herbert         First Version
 */
#include "mhdef.h"
#include "sel.h"
#include "selector.h"
#include "ccycle.h"
#include <assert.h>
#include <malloc.h>
#include <string.h>
#include <stdio.h>
#include <unistd.h>

#define SEL_CYCLE_TIME  80

SEL* sel_new()
{
    int i = 0;
    SEL *sel = (SEL*)malloc(sizeof (SEL));

    ccycle_init(&sel->cycle);
    ccycle_init(&sel->reset_cycle);

    timer_init(&sel->timer);

    for (i = 0; i < 16; i++)
    {
        sel->state[i] = 0xFF;
        sel->state_bk[i] = 0xFF;
    }

    sel->exec = selector_exec;
    sel->reset = selector_reset;
    sel->reset_all = selector_reset_all;

    return sel;
}

void sel_set_cycle(SEL *sel, CCYCLE *cycle, CCYCLE *reset_cycle)
{
    assert(sel != NULL);
    assert(cycle != NULL);
    assert(reset_cycle != NULL);

    memcpy(&sel->cycle, cycle, sizeof (CCYCLE));
    memcpy(&sel->reset_cycle, reset_cycle, sizeof (CCYCLE));
}

/*
 * @param sel: 纱嘴对象
 * @param group: 组序号，从左机头到右机头从左往右依次为0-15
 * @param index: 纱嘴的组内序号0-7代表刀片1-8
 */
int sel_exec(MH_UDP *pudp, SEL *sel, ActType type, int group, int index)
{
    assert(sel != NULL);
    assert((group >= 0) && (group < 16));
    assert((index >= 0) && (index < 8));

    if (type == ACT)
    {
        sel->state[group] ^= 0x01 << index;

        return sel->exec(pudp, index, sel->state);
    }

    sel->state[group] |= 0x01 << index;

    return sel->reset(pudp, group, index);
}

int sel_exec_group(MH_UDP *pudp, SEL *sel, int group)
{
    assert(sel != NULL);
    assert((group >= 0) && (group < 16));
    int ret;
    uchar i = 0;

    uchar group_state = sel_get_group_state(sel, group);

    if (group_state == UP)
    {
        for(i = 0; i < 8; i++)
        {
            sel->state[group] |= 0x01 << i;
            ret = selector_group_exec(pudp, i, sel->state);
            usleep(100000);
        }
    }
    else
    {
        for(i = 0; i < 8; i++)
        {
            sel->state[group] &= 0xfe << i;
            ret = selector_group_exec(pudp, i, sel->state);
            usleep(100000);
        }
    }
     return ret;
}
/*
 * @param sel: 选针器对象
 * @param ctype: 0-左机头；1-右机头
 * @param index: 组内序号
 * @note: 复位所有选针器的第index个刀片
 */
int sel_reset_all(MH_UDP *pudp, SEL *sel, int ctype, int index)
{
    assert(sel != NULL);

    int i = 0;

    for (i = 0; i < 8; i++)
    {
        sel->state[ctype * 8 + i] |= 0x01 << index;
    }

    return sel->reset_all(pudp, index, ctype);
}

int sel_exec_all(MH_UDP *pudp, SEL *sel, ActType type, int ctype, int index)
{
    assert(sel != NULL);

    int i = 0;
    if (type == ACT)
    {
        for (i = 0; i < 8; i++)
        {
            sel->state[ctype * 8 + i] ^= 0x01 << index;
        }
    }
    else
    {
        for (i = 0; i < 8; i++)
        {
            sel->state[ctype * 8 + i] |= 0x01 << index;
        }
    }

    return sel->exec(pudp, index, sel->state);
}

/*
 * @param sel: 选针器对象
 * @note: 执行单个循环和整组循环
 */
int sel_exec_cycle(MH_UDP *pudp, void *user_data)
{
    assert(user_data != NULL);

    SEL *sel = (SEL*)user_data;
    int group = -1;
    int index = -1;
    CCYCLE *cycle = NULL;
    ActType type = RESET;

    if (ccycle_get_state(&sel->reset_cycle) != CYCLE_STOP)
    {
        type = RESET;
        cycle = &sel->reset_cycle;
    }
    else if (ccycle_get_state(&sel->cycle) != CYCLE_STOP)
    {
        type = ACT;
        cycle = &sel->cycle;
    }

    if (cycle == NULL)
    {
        return 0;
    }


    group = cycle->group;
    index = cycle->index;

    if (ccycle_get_state(cycle) == CYCLE_READY)
    {
        ccycle_set_state(cycle, CYCLE_EXEC);
    }
    else
    {
        FEEDBACK fb;
        int ret = 0;
        memset(&fb, 0, sizeof (FEEDBACK));

        ret = feedback_get_error_state(pudp, &fb, (group > 7));

        ret = sel_encount_error(sel, &fb);

        if (ret < 0)
        {
            printf("encount error\n");
            return ret;
        }

        ccycle_exec_index(cycle);

        if (type == RESET)
        {
            /* 选针器循环时，所有刀片一起动，所以不考虑group */
            if (ccycle_get_index(cycle) == ccycle_get_start_index(cycle))
            {
                if (sel->resetall && (ccycle_get_group(cycle) < 8))
                {
                    /** 全部复位 */
                    /* 再复位右机头 */
                    ccycle_set_group(cycle, 8);
                }
                else
                {
                    ccycle_stop(cycle);
                    if (ccycle_get_state(&sel->cycle) != CYCLE_STOP)
                    {
                        /* 执行动作循环 */
                        timer_start(&sel->timer, 0, SEL_CYCLE_TIME, sel_exec_cycle);
                    }
                    return 0;
                }
            }
        }

        group = ccycle_get_group(cycle);
        index = ccycle_get_index(cycle);

    }

    if (group < 0 || index < 0)
    {
        return -1;
    }
    timer_start(&sel->timer, 0, SEL_CYCLE_TIME, sel_exec_cycle);

    if (sel->all_cycle)
    {
        return sel_exec_all(pudp, sel, type, (group > 7), index);
    }
    else if (sel->resetall)
    {
        return sel_reset_all(pudp, sel, (group > 7), index);
    }
    return sel_exec(pudp, sel, type, group, index);
}


int sel_get_next_diff(SEL *sel, CCYCLE *cycle, int *group, int *index)
{
    assert(sel != NULL);
    assert(cycle != NULL);
    assert(group != NULL);
    assert(index != NULL);

    do
    {
        int filter = 0;
        ccycle_exec(cycle);

        if (ccycle_complete(cycle))
        {
            return FALSE;
        }

        *group = ccycle_get_group(cycle);
        *index = ccycle_get_index(cycle);

        filter = 0x01 << *index;
        if (((sel->state[*group] ^ sel->state_bk[*group]) & filter) == 0)
        {
            /* 状态相同 */
            continue;
        }

        break;
    } while (1);

    return TRUE;
}

int sel_restore(MH_UDP *pudp, void *user_data)
{
    assert(user_data != NULL);

    SEL *sel = (SEL*)user_data;
    int group = -1;
    int index = -1;
    CCYCLE *cycle = NULL;

    cycle = &sel->reset_cycle;

    if (ccycle_get_state(cycle) == CYCLE_STOP)
    {
        return 0;
    }


    if (ccycle_get_state(cycle) == CYCLE_READY)
    {
        int filter = 0;
        ccycle_set_state(cycle, CYCLE_EXEC);
        group = cycle->group;
        index = cycle->index;

        filter = 0x01 << index;

        if (((sel->state[group] ^ sel->state_bk[group]) & filter) == 0)
        {
            if (!sel_get_next_diff(sel, cycle, &group, &index))
            {
                ccycle_stop(cycle);
                return 0;
            }
        }
    }
    else
    {
        FEEDBACK fb;

        int ret = feedback_get_error_state(pudp, &fb, (group > 7));

        if (ret < 0)
        {
            return ret;
        }

        ret = sel_encount_error(sel, &fb);

        if (ret < 0)
        {
            printf("encount error\n");
            return ret;
        }

        if (!sel_get_next_diff(sel, cycle, &group, &index))
        {
            ccycle_stop(cycle);
            return 0;
        }
    }

    if (group < 0 || index < 0)
    {
        return -1;
    }

    timer_start(&sel->timer, 0, SEL_CYCLE_TIME, sel_restore);

    return sel_exec(pudp, sel, ACT, group, index);
}

/*
 * @note: 用于检测单个测试的错误
 */
int sel_check_error(MH_UDP *pudp, void *user_data)
{
    assert(user_data != NULL);
    SEL *sel = (SEL*)user_data;
    FEEDBACK fb;
    int ret = 0;
    int group = ccycle_get_group(&sel->cycle);

    memset(&fb, 0, sizeof (FEEDBACK));

    ret = feedback_get_error_state(pudp, &fb, (group > 7));
    if (ret < 0)
    {
        return ret;
    }

    ret = sel_encount_error(sel, &fb);

    if (ret < 0)
    {
        return ret;
    }

    return 0;
}

int sel_exec_timer(MH_UDP *pudp, SEL *sel)
{
    assert(sel != NULL);
    return timer_exec(pudp, &sel->timer, (void*)sel);
}

/*
 * @param sel: 选针器对象
 * @param state: 从下位机读取到的纱嘴状态
 * @param size: state数组大小
 */
void sel_set_state(SEL *sel, uchar *state, int size)
{
    assert(sel != NULL);
    assert(state != NULL);

    memcpy(sel->state, state, size);
    memcpy(sel->state_bk, state, size);
}

/*
 * @param sel: 选针器对象
 * @param state[out]:获取到的纱嘴状态bit0-7代表１－８号纱嘴
 * @param size: state数组大小
 */
void sel_get_state(SEL *sel, uchar *state, int size)
{
    assert(sel != NULL);
    assert(state != NULL);

    memcpy(state, sel->state, size);
}

void sel_set_group_state(SEL *sel, uchar group_state, int group)
{
    assert(sel !=NULL);

    sel->group_state[group] = group_state;
}

uchar sel_get_group_state(SEL *sel, int group)
{
    assert(sel != NULL);

    return sel->group_state[group] ;
}

void sel_stop_cycle(SEL *sel)
{
    assert(sel != NULL);
    timer_stop(&sel->timer);
    ccycle_stop(&sel->reset_cycle);
    ccycle_stop(&sel->cycle);
}

/*
 * @note: 判断是否遇到错误
 */
int sel_encount_error(SEL *sel, FEEDBACK *fb)
{
    if (fb != NULL)
    {
        if (fb->error.sel)
        {
            return CRGERROR_SEL;
        }
    }
    return 0;
}

BOOL sel_reset_complete(SEL *sel)
{
    assert(sel != NULL);

    return (ccycle_get_state(&sel->reset_cycle) == CYCLE_STOP);
}

void sel_start_timer(SEL *sel, TIMEOUT_FUNC pfunc, BOOL now)
{
    assert(sel != NULL);
    if (now)
    {
        timer_start(&sel->timer, SEL_CYCLE_TIME, SEL_CYCLE_TIME, pfunc);
    }
    else
    {
        timer_start(&sel->timer, 0, SEL_CYCLE_TIME, pfunc);
    }
}

void sel_set_all_cycle(SEL *sel, uchar all_cycle)
{
    assert(sel != NULL);
    sel->all_cycle = all_cycle;
}

void sel_set_reset_all(SEL *sel, uchar resetall)
{
    assert(sel != NULL);
    sel->resetall = resetall;
}

CCYCLE* sel_get_cycle(SEL *sel)
{
    assert(sel != NULL);
    return &sel->cycle;
}


BOOL sel_need_restore(SEL *sel)
{
    assert(sel != NULL);
    return memcmp(sel->state, sel->state_bk, sizeof (sel->state));
}
